package excmy

import (
	"errors"
	"fmt"
	"github.com/xuri/excelize/v2"
	"strconv"
)

type Cell struct {
	Row    uint
	Column string
	*Sheet
	//StyleInt int
}

// 测试使用，用于获取当前
type Line struct {
	RowNumber uint
	Cells     map[string]*Cell
}

//func NewFile() *excelize.File {
//	excelFile := excelize.NewFile()
//	return excelFile
//}

// SelectSheet 用于选中一个文件中的Sheet对象，注意！不会新建Sheet对线
// 受制于框架影响无法使用返回报错
func SelectSheet(file *excelize.File, name string) *Sheet {
	sheet := new(Sheet)
	sheet.Name = name
	sheet.File = file
	return sheet
}

// NewSheet 用于创建Sheet
func NewSheet(file *excelize.File, name string) *Sheet {
	_, err := file.NewSheet(name)
	if err != nil {
		panic(err)
	}
	sheet := new(Sheet)
	sheet.Name = name
	sheet.File = file
	return sheet
}

// Write 从本格开始写矩阵
func (c *Cell) Write(in [][]string) error {
	//标记头cell
	lineHeadCell := c
	for _, data := range in {
		//fmt.Println("lineHeadCell.Row", lineHeadCell.Row)
		lineHeadCell.Sheet.File.SetSheetRow(lineHeadCell.Sheet.Name, lineHeadCell.Location(), &data)
		lineHeadCell = lineHeadCell.Down()
	}
	return nil
}
func (c *Cell) WriteInterFace(in [][]interface{}) error {
	//标记头cell
	lineHeadCell := c
	for _, data := range in {
		//fmt.Println("lineHeadCell.Row", lineHeadCell.Row)
		lineHeadCell.Sheet.File.SetSheetRow(lineHeadCell.Sheet.Name, lineHeadCell.Location(), &data)
		lineHeadCell = lineHeadCell.Down()
	}
	return nil
}

// Write 从本格开始想下读矩阵，to是到哪一列,！！目前！！必须要跨列，也就是不能B到B，必须B到C
func (c *Cell) Read(to string) [][]string {
	lineHeadCell := c //确定每一行的头，只Down
	from := c.Column

	re := make([][]string, 0)
	for i := 0; ; i++ {
		if lineHeadCell.Value() == "" && lineHeadCell.Right().Value() == "" { //判断是否是最后一行的条件是前两个不为空
			break
		}

		thisLineRes := c.Sheet.ReadLine(int(lineHeadCell.Row), from, to)
		re = append(re, thisLineRes)
		lineHeadCell = lineHeadCell.Down()
	}

	return re
}

// Write 从本格开始想下读矩阵，to是到哪一列，读后的结果是interface{},需要指定每一行的类型
func (c *Cell) ReadAsInterFace(to string, cellType []string) [][]interface{} {
	lineHeadCell := c //确定每一行的头，只Down
	from := c.Column

	if columnToNumber(to)-columnToNumber(c.Column)+1 != len(cellType) {
		panic("ReadAsInterFace，err！cellType长度与指定长度不相等")
	}

	re := make([][]interface{}, 0)
	for i := 0; ; i++ {
		if lineHeadCell.Value() == "" && lineHeadCell.Right().Value() == "" { //判断是否是最后一行的条件是前两个不为空
			break
		}

		thisLineRes := c.Sheet.ReadLineToInterface(int(lineHeadCell.Row), from, to, cellType)
		re = append(re, thisLineRes)
		lineHeadCell = lineHeadCell.Down()
	}

	return re
}

func (c *Cell) ValueInterface(cellType string) interface{} {
	value, err := c.File.GetCellValue(c.Sheet.Name, c.Location())
	if err != nil {
		fmt.Println(err)
		return nil
	}
	//fmt.Println("调试！！！cell109", c.Value(), cellType)

	switch cellType {
	case "string":
		return value
	case "int":
		intValue, err := strconv.Atoi(value)
		if err != nil {
			panic("Error converting to INT:" + c.Value())
			return nil
		}
		return intValue
	case "float":
		floatValue, err := strconv.ParseFloat(value, 64)
		if err != nil {
			panic("Error converting to float:" + c.Value())
			return nil
		}
		return floatValue
	default:
		panic("Unsupported cell type:" + cellType)
		return nil
	}
}

// Line 返回当前Cell所在的行
func (c *Cell) Line() *Line {
	newline := new(Line)
	newline.RowNumber = c.Row
	firstcell, err := c.Sheet.NewCell(fmt.Sprintf("%s%d", c.Sheet.boundary[0], c.Row))
	if err != nil {
		fmt.Println(err)
		panic("错误的cell in(c *Cell)Line(row uint)")
	}

	Cells := make(map[string]*Cell)
	j := 0
	tempCell := firstcell
	for i := columnToNumber(c.Sheet.boundary[0]); i <= columnToNumber(c.Sheet.boundary[1]); i++ {
		Cells[c.Sheet.Fields[j]] = tempCell
		tempCell = tempCell.Right()
		j++
	}
	newline.Cells = Cells
	return newline
}

// IFboundary 返回判断是否是在边界，如果是，第二个参数left是左边界，right是右边界
func (c *Cell) IFboundary() (bool, string) {
	if c.Column == c.Sheet.boundary[0] {
		return true, "left"
	} else if c.Column == c.Sheet.boundary[1] {
		return true, "right"
	}

	return false, ""
}

func (c *Cell) SetCellValue(value interface{}) error {
	err := c.File.SetCellValue(c.Sheet.Name, c.Location(), value)
	//fmt.Println("set ", c.Location(), ":", value)
	if err != nil {
		return err
	}
	return nil
}

func (c *Cell) Value() string {
	value, err := c.File.GetCellValue(c.Sheet.Name, c.Location())
	if err != nil {
		fmt.Println(err)
		return ""
	}
	return value
}

func (c *Cell) Up() *Cell {
	if c.Row <= 1 {
		panic(errors.New("c.Row() can not < 1"))
	}

	newCell := new(Cell)
	newCell.Row = c.Row - 1
	newCell.Column = c.Column
	newCell.Sheet = c.Sheet

	return newCell
	//return &Cell{c.Row - 1, c.Column, c.Sheet}
}

func (c *Cell) Down() *Cell {
	newCell := new(Cell)
	newCell.Row = c.Row + 1
	newCell.Column = c.Column
	newCell.Sheet = c.Sheet

	return newCell
	//return &Cell{c.Row + 1, c.Column, c.Sheet}
}

// NextRowFrom 返回下一列的某一单元格
func (c *Cell) NextRowFrom(where string) *Cell {
	newCell := new(Cell)
	newCell.Row = c.Row + 1
	newCell.Column = where
	newCell.Sheet = c.Sheet
	return newCell
	//return &Cell{c.Row + 1, where, c.Sheet}
}

// Right 返回当前单元格右侧相邻的单元格。
func (c *Cell) Right() *Cell {
	rCell := new(Cell)
	rCell.Row = c.Row
	rCell.Sheet = c.Sheet

	columnNumber := columnToNumber(c.Column)
	columnNumber++ // 向右移动一列

	rCell.Column = numberToColumn(columnNumber)

	return rCell
}

func (c *Cell) RowAnotherCell(num string) *Cell {
	newCell := new(Cell)
	newCell.Row = c.Row
	newCell.Column = num
	newCell.Sheet = c.Sheet
	return newCell
}

// Left 返回当前单元格左侧相邻的单元格。
func (c *Cell) Left() *Cell {
	lCell := new(Cell)
	lCell.Row = c.Row
	lCell.Sheet = c.Sheet

	columnNumber := columnToNumber(c.Column)
	columnNumber-- // 向左移动一列

	lCell.Column = numberToColumn(columnNumber)

	return lCell
}

// columnToNumber 将列标识（如 "A", "B", ..., "Z", "AA", "AB", ...）转换为数字。
func columnToNumber(col string) int {
	number := 0
	for i := 0; i < len(col); i++ {
		number = number*26 + (int(col[i]-'A') + 1)
	}
	return number
}

// numberToColumn 将数字转换回列标识。
func numberToColumn(number int) string {
	if number == 0 {
		panic("入参为0")
	}
	if number == 1 {
		return "A"
	}
	var result []rune
	for number > 0 {
		mod := number % 26
		if mod == 0 {
			result = append([]rune{'Z'}, result...)
			number -= 1
		} else {
			result = append([]rune{rune(mod - 1 + 'A')}, result...)
		}
		number /= 26
	}
	return string(result)
}

//func(cell *Cell) ReadRow (to string) (data []string) {
//	data = make([]string, 0)
//	tempcell := cell
//	for  {
//
//	}
//}

func (cell *Cell) WriteRow(data []string) {
	tempcell := cell
	for _, d := range data {
		err := tempcell.SetCellValue(d)
		if err != nil {
			fmt.Println(err)
			panic(err)
		}
		tempcell = tempcell.Down()
	}
}

func (cell *Cell) Location() string {
	return fmt.Sprintf("%s%d", cell.Column, cell.Row)
}
